﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO.Ports;
using System.Timers;
using DAQ.PROTOCOL;
using DAQ.Common.BTSR_V1;
using Modbus;
using System.Net;
using System.Net.Sockets;
using Modbus.Device;
using Modbus.Data;
using System.Windows.Forms;

namespace DAQ.Common
{

    public class CWMCmn
    {
        SerialPort port;
        public static readonly CWMCmn Inst = new CWMCmn();
        List<Config.CfgItem> _cfgs = new List<Config.CfgItem>();
        ModbusSlave slave = null;
        TcpListener tcpListener=null;

        public DataStore DataStore { get => slave.DataStore; }
        private CWMCmn()
        {
            CreateCWMport();

            CreateModbusSlave(Config.GetConfig(CFGS.MODBUS, CFGS.IP));
        }

        public void CreateCWMport()
        {
            string PortName = Config.GetConfig(CFGS.BTSR_COM, CFGS.PortName);
            int BaudRate = int.Parse(Config.GetConfig(CFGS.BTSR_COM, CFGS.BaudRate));
            if (port != null)
                port.Close();
            port = new SerialPort(PortName, BaudRate);
        }

        public void CreateModbusSlave(string IP)
        {
            try
            {
                int iport = 9600;
                IPHostEntry ipEntry = Dns.GetHostEntry(Dns.GetHostName());
                IPAddress[] addr = ipEntry.AddressList.Where(x => x.AddressFamily == AddressFamily.InterNetwork).ToArray();
                if (slave != null)
                {
                    slave.Dispose();
                }
                if (tcpListener != null)
                {
                    tcpListener.Stop();
                }
                tcpListener = new TcpListener(IPAddress.Parse(IP), iport);

                tcpListener.Start();
                slave = ModbusTcpSlave.CreateTcp(1, tcpListener);
                slave.DataStore = DataStoreFactory.CreateDefaultDataStore();
                slave.Listen();
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }
       

        /// <summary>
        /// Identify the CWF
        /// </summary>
        /// <param name="Identification_code"></param>
        public int IdentifycationProcedure(byte Identification_code)
        {
            int res = -1;
            BTSRSerialport.ResetEvent.Reset();
            port.SendBuffer_9bit(true, 0xfd, 0xfd, 0xfd);
            byte[] recv = port.Read(20000);
            if (recv == null)
                return -1; //通信超時
            if(recv.Length>0)
            {
                if (recv[0] == 0xFD)
                {
                    Wait.Delay(30);
                    port.SendBuffer_9bit(false, Identification_code);
                    res= 0;
                }
                else
                {
                    res= -2; //返回值不正確
                }
            }
            port.SendBuffer_9bit(false, 0xFC);
            BTSRSerialport.ResetEvent.Set();
            return res;       
        }

        public PC_LINK GetPC_LINK(int id)
        {
            byte[] bytes = PC_LINK.GetSendBytes((byte)(id));
            int i = 10;
            byte[] result = null;
            while (i-->0)
            {
                if(port.IsOpen)
                port.DiscardInBuffer();
                 result = port.Request(bytes,52,50);
                if (result != null && result.VerifyChecksum())
                {
                    PC_LINK pC_LINK = new PC_LINK(result);
                    pC_LINK.COM_ID = id;
                    return pC_LINK;
                }
            }
            return null;       
        }
        public ADVANCED_TENSION_READ GetADVANCE_TENSION_READ(int id)
        {
            byte[] bytes = ADVANCED_TENSION_READ.GetSendBytes((byte)(id));
            int i = 5;
            byte[] result = null;
            while (i-- > 0)
            {
                if (port.IsOpen)
                    port.DiscardInBuffer();
                result = port.Request_v2(bytes, 74, 100);
                if (result != null && result.VerifyChecksum())
                {
                    ADVANCED_TENSION_READ tension_read = new ADVANCED_TENSION_READ(result);
                    return tension_read;
                }
            }
            return null;
        }

        /// <summary>
        /// 取消配置身份ID
        /// </summary>
        /// <param name="Identification_code"></param>
        public void CancelIdentifycationProcedure()
        {
            BTSRSerialport.ResetEvent.Reset();    
            port.SendBuffer_9bit(false, 0xFC);
            Wait.Delay(50);
            port.SendBuffer_9bit(false, 0xFB);
        }
    }

    public class DeviceModel
    {
        public int ID { get; set; }
        public string Description { get; set; }
        public PC_LINK PC_LINK { get; set; }
    }
    public class DeviceModelManager
    {
        public static readonly DeviceModelManager Inst = new DeviceModelManager();
        List<Config.CfgItem> _cfgs = new List<Config.CfgItem>();
        List<DeviceModel> _devices = new List<DeviceModel>();
        public List<DeviceModel> GetDevices(List<Config.CfgItem> cfgs )
        {
            var q = cfgs.Where(x => x.Key == CFGS.BTSR_DEV);
            if (q.Count() > 0)
            {
                foreach (var a in q)
                {
                    if (_devices.Exists(x => x.Description == a.Key))
                        _devices.ForEach((x) =>
                        {
                            if (x.Description == a.Key)
                            {
                                x.ID = int.Parse(a.Value);
                            }
                        });
                    else
                    {
                        _devices.Add(new DeviceModel() { ID = int.Parse(a.Value), Description = a.Key });
                    }
                }
            }
            return _devices;
        }

        public void SetPCLink(string Descrip, PC_LINK pC_LINK)
        {
            if (_devices.Exists(x => x.Description == Descrip))
            {
                _devices.ForEach(x => { x.PC_LINK = pC_LINK; });
            }
            else
            {
                throw new Exception("No Valid Device Config");
            }
        }
    }
}
